home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / tkern10.zip / SRC\WINDOW.C < prev    next >
Text File  |  1994-05-16  |  30KB  |  1,401 lines

  1. /*
  2.  *  This file forms part of "TKERN" - "Troy's Kernel for Windows".
  3.  *
  4.  *  Copyright (C) 1994  Troy Rollo <troy@cbme.unsw.EDU.AU>
  5.  *
  6.  *  This library is free software; you can redistribute it and/or
  7.  *  modify it under the terms of the GNU Library General Public
  8.  *  License as published by the Free Software Foundation; either
  9.  *  version 2 of the License, or (at your option) any later version.
  10.  *
  11.  *  This library is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  *  Library General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU Library General Public
  17.  *  License along with this library; if not, write to the Free
  18.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #include <windows.h>
  22. #include <windowsx.h>
  23. #include <memory.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <errno.h>
  27. #include <sys/tfile.h>
  28. #include <sys/tdevice.h>
  29. #include <sys/tkwin.h>
  30.  
  31. void    far    tkern_deliver_signal(    int    nDevice,
  32.                     int    nFile,
  33.                     int    nSignal);
  34.  
  35. static    BOOL    bRegistered = 0;
  36. static    int    iDevice;
  37.  
  38. extern    HINSTANCE    hInstance;
  39. extern    int    nError;
  40.  
  41. extern    void    UnlockManager(void);
  42. extern    void    LockManager(void);
  43. extern    void    FlushMessages(void);
  44. extern    void    tkern_wakeup_call(void);
  45.  
  46. static    int    window_destroy(HWND hWnd);
  47.  
  48. #define    SC_COPY    5000
  49. #define    SC_PASTE    5001
  50. #define    SC_COPYPASTE    5002
  51.  
  52. #define    DEF_MAXLINES    100
  53. #define    DEF_SCROLLLINES    5
  54.  
  55. struct    line
  56. {
  57.     struct    line *plNext;
  58.     struct    line *plPrev;
  59.     char    *pchLine;
  60. };
  61.  
  62. struct    per_window
  63. {
  64.     struct    line    *pw_head;
  65.     struct    line    *pw_tail;
  66.     struct    line    *pw_inhead;
  67.     struct    line    *pw_intail;
  68.     struct    line    *pw_history;
  69.     struct    line    *pw_hishead;
  70.     struct    line    *pw_histail;
  71.     int    nUnscrolledLines;
  72.     int    nHistory;
  73.     int    nHistMax;
  74.     int    nScrollLines;
  75.     int    nLines;            /* Counter so we can keep the list reasonable */
  76.     int    nLinesMax;
  77.     int    cxChar;
  78.     int    cyChar;
  79.     int    nScrollPos;
  80.     HWND    hEdit;
  81.     int    xEditStart;
  82.     POINT    ptMarkStart;
  83.     POINT    ptMarkEnd;
  84.     BOOL    bMarkValid;
  85.     BOOL    bHaveMouse;
  86.     BOOL    bProgramClosed;
  87. };
  88.  
  89. #define    ENTER_HIT    WM_USER + 1000
  90. #define    UP_HIT        WM_USER + 1001
  91. #define DOWN_HIT    WM_USER + 1002
  92.  
  93. WNDPROC    NormalEditWndProc = 0;
  94.  
  95. FARPROC    FakeEditThunk = 0;
  96.  
  97. int    far    pascal    _export
  98. FakeEditWndProc(    HWND    hWnd,
  99.             UINT    wMsg,
  100.             WPARAM    wParam,
  101.             LPARAM    lParam)
  102. {
  103.     if (wMsg == WM_KEYDOWN)
  104.     {
  105.         if (wParam == VK_UP)
  106.         {
  107.             SendMessage(GetParent(hWnd), UP_HIT, 0, 0);
  108.             return 0;
  109.         }
  110.         else if (wParam == VK_DOWN)
  111.         {
  112.             SendMessage(GetParent(hWnd), DOWN_HIT, 0, 0);
  113.             return 0;
  114.         }
  115.     }
  116.     if (wMsg == WM_CHAR)
  117.     {
  118.         if (wParam == VK_RETURN)
  119.         {
  120.             SendMessage(GetParent(hWnd), ENTER_HIT, 0, 0);
  121.             return 0;
  122.         }
  123.         else if (wParam == VK_TAB)
  124.         {
  125.             SendMessage(hWnd, EM_REPLACESEL, 0, (long) "\t");
  126.             return 0;
  127.         }
  128.         else if (wParam == 3)
  129.         {
  130.             tkern_deliver_signal(iDevice,
  131.                          (int) GetParent(hWnd),
  132.                          2);
  133.             return 0;
  134.         }
  135.     }
  136.     return (*NormalEditWndProc)(hWnd, wMsg, wParam, lParam);
  137. }
  138.  
  139. static    void
  140. MoveMark(struct per_window *pw,
  141.      int nLines)
  142. {
  143.     if (pw->bMarkValid)
  144.     {
  145.         pw->ptMarkStart.y += nLines;
  146.         pw->ptMarkEnd.y += nLines;
  147.     }
  148. }
  149.  
  150. static    void
  151. screen_to_row(    HWND    hWnd,
  152.         struct    per_window *pw,
  153.         int    x,
  154.         int    y,
  155.         int    *xOut,
  156.         int    *yOut)
  157. {
  158.     RECT    rcClient;
  159.     int    cyLastRow;
  160.     struct line *pl;
  161.     int    i, j;
  162.  
  163.     GetClientRect(hWnd, &rcClient);
  164.  
  165.     y = rcClient.bottom - y;
  166.     cyLastRow = pw->cyChar + pw->cyChar / 5 * 2;
  167.     if (y < cyLastRow)
  168.     {
  169.         *yOut = 0;
  170.     }
  171.     else
  172.     {
  173.         *yOut = (y - cyLastRow) / pw->cyChar + 1;
  174.     }
  175.  
  176.     if (*yOut > 0)
  177.         *yOut += pw->nScrollPos;
  178.  
  179.     for (i = *yOut, pl = pw->pw_tail;
  180.          i && pl;
  181.          i--, pl = pl->plPrev);
  182.  
  183.     if (!pl || !pl->pchLine)
  184.     {
  185.         *xOut = 0;
  186.         return;
  187.     }
  188.  
  189.     x = x / pw->cxChar;
  190.  
  191.     for (i = j = 0; x > j && pl->pchLine[i]; i++)
  192.     {
  193.         if (pl->pchLine[i] == '\t')
  194.             j += 8 - j % 8;
  195.         else
  196.             j++;
  197.     }
  198.     *xOut = i;
  199. }
  200.  
  201. static    void
  202. RedrawPoints(    HWND    hWnd,
  203.         struct per_window *pw,
  204.         POINT    ptStart_,
  205.         POINT    ptEnd_)
  206. {
  207.     POINT    ptStart, ptEnd;
  208.     RECT    rcRedraw;
  209.  
  210.     if (ptStart_.y > ptEnd_.y)
  211.     {
  212.         ptStart = ptStart_;
  213.         ptEnd = ptEnd_;
  214.     }
  215.     else if (ptStart_.y < ptEnd_.y)
  216.     {
  217.         ptStart = ptEnd_;
  218.         ptEnd = ptStart_;
  219.     }
  220.     else if (ptStart_.x < ptEnd_.x)
  221.     {
  222.         ptStart = ptStart_;
  223.         ptEnd = ptEnd_;
  224.     }
  225.     else
  226.     {
  227.         ptStart = ptEnd_;
  228.         ptEnd = ptStart_;
  229.     }
  230.     if (ptEnd.y > 0)
  231.     {
  232.         ptEnd.y -= pw->nScrollPos;
  233.         if (ptEnd.y < 0)
  234.             ptEnd.y = 0;
  235.     }
  236.     if (ptStart.y > 0)
  237.     {
  238.         ptStart.y -= pw->nScrollPos;
  239.         if (ptStart.y < 1)
  240.             ptStart.y = 1;
  241.     }
  242.  
  243.     if (ptStart.y < ptEnd.y)
  244.         return;
  245.     GetClientRect(hWnd, &rcRedraw);
  246.     rcRedraw.top = rcRedraw.bottom - pw->cyChar * (ptStart.y + 1) - pw->cyChar / 5 * 2;
  247.     if (ptEnd.y)
  248.         rcRedraw.bottom -= pw->cyChar * ptEnd.y + pw->cyChar / 5 * 2;
  249.     InvalidateRect(hWnd, &rcRedraw, TRUE);
  250. }
  251.  
  252. static    void
  253. MouseDown(    HWND    hWnd,
  254.         struct per_window *pw,
  255.         int    x,
  256.         int    y)
  257. {
  258.     if (pw->bMarkValid)
  259.     {
  260.         pw->bMarkValid = FALSE;
  261.         RedrawPoints(hWnd, pw, pw->ptMarkStart, pw->ptMarkEnd);
  262.     }
  263.     screen_to_row(hWnd, pw, x, y, &pw->ptMarkStart.x, &pw->ptMarkStart.y);
  264.     pw->ptMarkEnd = pw->ptMarkStart;
  265.     RedrawPoints(hWnd, pw, pw->ptMarkStart, pw->ptMarkEnd);
  266.     SetCapture(hWnd);
  267.     pw->bHaveMouse = TRUE;
  268.     pw->bMarkValid = TRUE;
  269. }
  270.  
  271. static    void
  272. MouseMove(    HWND    hWnd,
  273.         struct per_window *pw,
  274.         int    x,
  275.         int    y)
  276. {
  277.     POINT    ptTemp;
  278.  
  279.     ptTemp = pw->ptMarkEnd;
  280.     screen_to_row(hWnd, pw, x, y, &pw->ptMarkEnd.x, &pw->ptMarkEnd.y);
  281.     RedrawPoints(hWnd, pw, ptTemp, pw->ptMarkEnd);
  282. }
  283.  
  284. static    void
  285. MouseUp(struct per_window *pw)
  286. {
  287.     ReleaseCapture();
  288.     pw->bHaveMouse = FALSE;
  289. }
  290.         
  291.  
  292. static    void
  293. get_mark_coordinates(    struct    per_window *pw,
  294.             POINT    *ptOne,
  295.             POINT    *ptTwo)
  296. {
  297.     if (pw->ptMarkStart.y > pw->ptMarkEnd.y)
  298.     {
  299.         *ptOne = pw->ptMarkStart;
  300.         *ptTwo = pw->ptMarkEnd;
  301.     }
  302.     else if (pw->ptMarkStart.y < pw->ptMarkEnd.y)
  303.     {
  304.         *ptOne = pw->ptMarkEnd;
  305.         *ptTwo = pw->ptMarkStart;
  306.     }
  307.     else if (pw->ptMarkStart.x < pw->ptMarkEnd.x)
  308.     {
  309.         *ptOne = pw->ptMarkStart;
  310.         *ptTwo = pw->ptMarkEnd;
  311.     }
  312.     else
  313.     {
  314.         *ptOne = pw->ptMarkEnd;
  315.         *ptTwo = pw->ptMarkStart;
  316.     }
  317. }
  318.  
  319.  
  320. static    int
  321. is_in_mark(    int    iRow,
  322.         struct per_window *pw,
  323.         int    *iMarkBoundary1,
  324.         int    *iMarkBoundary2)
  325. {
  326.     POINT    ptStart, ptEnd;
  327.  
  328.     if (!pw->bMarkValid)
  329.         return 0;
  330.     get_mark_coordinates(pw, &ptStart, &ptEnd);
  331.     if (ptStart.y > ptEnd.y)
  332.     {
  333.         if (ptEnd.y > iRow ||
  334.             ptStart.y < iRow)
  335.             return 0;
  336.         if (ptStart.y == iRow)
  337.         {
  338.             *iMarkBoundary1 = ptStart.x;
  339.             return 1;
  340.         }
  341.         if (ptEnd.y == iRow)
  342.         {
  343.             *iMarkBoundary1 = ptEnd.x;
  344.             return 2;
  345.         }
  346.         return 3;
  347.     }
  348.     else if (ptStart.y == iRow)
  349.     {
  350.         *iMarkBoundary1 = ptStart.x;
  351.         *iMarkBoundary2 = ptEnd.x;
  352.         return 4;
  353.     }
  354.     else
  355.     {
  356.         return 0;
  357.     }
  358. }
  359.  
  360. static    void
  361. PlaceEdit(    HWND    hWnd,
  362.         struct per_window *pw)
  363. {
  364.     RECT    rcLoc;
  365.  
  366.     GetClientRect(hWnd, &rcLoc);
  367.     rcLoc.left = pw->xEditStart;
  368.     rcLoc.top = rcLoc.bottom - pw->cyChar - pw->cyChar / 5;
  369.     if (pw->hEdit)
  370.     {
  371.         MoveWindow(pw->hEdit,
  372.                 rcLoc.left, rcLoc.top,
  373.                 rcLoc.right - rcLoc.left + 1,
  374.                 rcLoc.bottom - rcLoc.top + 1,
  375.                 TRUE);
  376.     }
  377.     else
  378.     {
  379.         pw->hEdit = CreateWindow(    "EDIT",
  380.                         "",
  381.                         WS_VISIBLE |
  382.                          WS_CHILD |
  383.                          ES_AUTOHSCROLL |
  384.                          ES_LEFT,
  385.                         rcLoc.left,
  386.                         rcLoc.top,
  387.                         rcLoc.right - rcLoc.left,
  388.                         rcLoc.bottom - rcLoc.top,
  389.                         hWnd,
  390.                         (HMENU) 100,
  391.                         hInstance,
  392.                         0
  393.                     );
  394.         if (!NormalEditWndProc)
  395.         {
  396.             NormalEditWndProc = (WNDPROC)
  397.                 GetWindowLong(pw->hEdit, GWL_WNDPROC);
  398.         }
  399.         if (!FakeEditThunk)
  400.         {
  401.             FakeEditThunk = MakeProcInstance((FARPROC) FakeEditWndProc, hInstance);
  402.         }
  403.         SetWindowLong(pw->hEdit, GWL_WNDPROC, (long) FakeEditThunk);
  404.     }
  405. }
  406.  
  407. static    void
  408. PaintWindow(    HWND    hWnd,
  409.         struct per_window *pw)
  410. {
  411.     PAINTSTRUCT    ps;
  412.     TEXTMETRIC    tm;
  413.     LOGFONT        lf;
  414.     int        cyChar;
  415.     int        cyInch;
  416.     int        yLocation;
  417.     int        nRows;
  418.     RECT        rcClient;
  419.     HFONT        hFont, hOldFont;
  420.     int        iRow, iTemp, iTotal;
  421.     struct line    *pl;
  422.     LONG        xExtent, xExtent2;
  423.     BOOL        bBottom = TRUE;
  424.     int        iMarkBoundary1, iMarkBoundary2;
  425.     COLORREF    crBG, crFG, crFGHigh, crBGHigh;
  426.  
  427.     crFG = GetSysColor(COLOR_WINDOWTEXT);
  428.     crBG = GetSysColor(COLOR_WINDOW);
  429.     crFGHigh = GetSysColor(COLOR_HIGHLIGHTTEXT);
  430.     crBGHigh = GetSysColor(COLOR_HIGHLIGHT);
  431.     if (pw->nUnscrolledLines)
  432.     {
  433.         if (!pw->nScrollPos)
  434.             ScrollWindow(hWnd, 0, -pw->nUnscrolledLines * pw->cyChar, 0, 0);
  435.         pw->nUnscrolledLines = 0;
  436.         PlaceEdit(hWnd, pw);
  437.         UpdateWindow(hWnd);
  438.     }
  439.     BeginPaint(hWnd, &ps);
  440.  
  441.     cyInch = GetDeviceCaps(ps.hdc, LOGPIXELSY);
  442.  
  443.     memset(&lf, 0, sizeof(lf));
  444.     lf.lfHeight = MulDiv(cyInch, 12, 72);
  445.     strcpy(lf.lfFaceName, "System");
  446.     lf.lfPitchAndFamily = FIXED_PITCH;
  447.     hFont = CreateFontIndirect(&lf);
  448.     hOldFont = SelectFont(ps.hdc, hFont);
  449.     GetTextMetrics(ps.hdc, &tm);
  450.     cyChar = tm.tmHeight + tm.tmExternalLeading;
  451.     GetClientRect(hWnd, &rcClient);
  452.     pw->cxChar = tm.tmAveCharWidth;
  453.     pw->cyChar = cyChar;
  454.     pl = pw->pw_tail;
  455.  
  456.     if (pw->pw_tail->pchLine)
  457.         xExtent = GetTabbedTextExtent(ps.hdc, 
  458.                           pl->pchLine,
  459.                           strlen(pl->pchLine),
  460.                           0, 0);
  461.     else
  462.         xExtent = 0;
  463.     pw->xEditStart = LOWORD(xExtent);
  464.  
  465.     PlaceEdit(hWnd, pw);
  466.  
  467.     nRows = (rcClient.bottom - ps.rcPaint.top) / cyChar + 1;
  468.  
  469.     for (iRow = 0, iTotal = 0, pl = pw->pw_tail,
  470.           yLocation = rcClient.bottom - cyChar;
  471.          pl && iTotal < nRows;
  472.          iRow++, iTotal++, pl = pl->plPrev)
  473.     {
  474.         if (iRow == 1 && pw->nScrollPos)
  475.         {
  476.             for (iTemp = 0; iTemp < pw->nScrollPos && pl; iTemp++, pl = pl->plPrev, iRow++);
  477.             if (!pl)
  478.                 break;
  479.         }
  480.         if (bBottom)
  481.         {
  482.             yLocation -= cyChar / 5;
  483.         }
  484.         if (pl->pchLine)
  485.         {
  486.             switch(is_in_mark(iRow, pw, &iMarkBoundary1, &iMarkBoundary2))
  487.             {
  488.             case 0: /* Not in a marked area */
  489.                 SetTextColor(ps.hdc, crFG);
  490.                 SetBkColor(ps.hdc, crBG);
  491.                 TabbedTextOut(ps.hdc, 0, yLocation,
  492.                           pl->pchLine, strlen(pl->pchLine),
  493.                           0, 0, 0);
  494.                 break;
  495.  
  496.             case 1: /* First line in a marked area */
  497.                 SetTextColor(ps.hdc, crFG);
  498.                 SetBkColor(ps.hdc, crBG);
  499.                 TabbedTextOut(ps.hdc, 0, yLocation,
  500.                           pl->pchLine, iMarkBoundary1,
  501.                           0, 0, 0);
  502.                 xExtent = GetTabbedTextExtent(ps.hdc, 
  503.                           pl->pchLine,
  504.                           iMarkBoundary1,
  505.                           0, 0);
  506.                 SetTextColor(ps.hdc, crFGHigh);
  507.                 SetBkColor(ps.hdc, crBGHigh);
  508.                 TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
  509.                         pl->pchLine + iMarkBoundary1,
  510.                         strlen(pl->pchLine) - iMarkBoundary1,
  511.                         0, 0, 0);
  512.                 break;
  513.  
  514.             case 2: /* Last line in a marked area */
  515.                 SetTextColor(ps.hdc, crFGHigh);
  516.                 SetBkColor(ps.hdc, crBGHigh);
  517.                 TabbedTextOut(ps.hdc, 0, yLocation,
  518.                           pl->pchLine, iMarkBoundary1,
  519.                           0, 0, 0);
  520.                 xExtent = GetTabbedTextExtent(ps.hdc, 
  521.                           pl->pchLine,
  522.                           iMarkBoundary1,
  523.                           0, 0);
  524.                 SetTextColor(ps.hdc, crFG);
  525.                 SetBkColor(ps.hdc, crBG);
  526.                 TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
  527.                         pl->pchLine + iMarkBoundary1,
  528.                         strlen(pl->pchLine) - iMarkBoundary1,
  529.                         0, 0, 0);
  530.                 break;
  531.  
  532.             case 3:    /* Entire line is in a marked area */
  533.                 SetTextColor(ps.hdc, crFGHigh);
  534.                 SetBkColor(ps.hdc, crBGHigh);
  535.                 TabbedTextOut(ps.hdc, 0, yLocation,
  536.                           pl->pchLine, strlen(pl->pchLine),
  537.                           0, 0, 0);
  538.                 break;
  539.  
  540.             case 4: /* Both first and last line in marked area */
  541.                 SetTextColor(ps.hdc, crFG);
  542.                 SetBkColor(ps.hdc, crBG);
  543.                 TabbedTextOut(ps.hdc, 0, yLocation,
  544.                           pl->pchLine, iMarkBoundary1,
  545.                           0, 0, 0);
  546.                 xExtent = GetTabbedTextExtent(ps.hdc, 
  547.                           pl->pchLine,
  548.                           iMarkBoundary1,
  549.                           0, 0);
  550.                 SetTextColor(ps.hdc, crFGHigh);
  551.                 SetBkColor(ps.hdc, crBGHigh);
  552.                 TabbedTextOut(ps.hdc, LOWORD(xExtent), yLocation,
  553.                         pl->pchLine + iMarkBoundary1,
  554.                         iMarkBoundary2 - iMarkBoundary1,
  555.                         0, 0, 0);
  556.                 xExtent2 = GetTabbedTextExtent(ps.hdc, 
  557.                           pl->pchLine + iMarkBoundary1,
  558.                           iMarkBoundary2 - iMarkBoundary1,
  559.                           0, 0);
  560.                 SetTextColor(ps.hdc, crFG);
  561.                 SetBkColor(ps.hdc, crBG);
  562.                 TabbedTextOut(ps.hdc, LOWORD(xExtent) + LOWORD(xExtent2),
  563.                         yLocation,
  564.                         pl->pchLine + iMarkBoundary2,
  565.                         strlen(pl->pchLine) - iMarkBoundary2,
  566.                         0, 0, 0);
  567.                 break;
  568.             }
  569.         }
  570.         yLocation -= cyChar;
  571.         if (bBottom)
  572.         {
  573.             yLocation -= cyChar / 5;
  574.             bBottom = FALSE;
  575.         }
  576.     }
  577.  
  578.     SelectFont(ps.hdc, hOldFont);
  579.     DeleteFont(hFont);
  580.     EndPaint(hWnd, &ps);
  581. }
  582.  
  583. void
  584. GotLine(struct per_window *pw)
  585. {
  586.     struct    line *plTemp, *plNew;
  587.     char    *pchData;
  588.     int    nLen;
  589.  
  590.     pw->pw_history = 0;
  591.     nLen = GetWindowTextLength(pw->hEdit);
  592.  
  593.     /* Once for the input queue */
  594.     pchData = (char *) malloc(nLen + 1);
  595.     GetWindowText(pw->hEdit, pchData, nLen + 1);
  596.     pchData[nLen] = 0;
  597.     plNew = (struct line *) malloc(sizeof(struct line));
  598.     plNew->plNext = 0;
  599.     plNew->plPrev = pw->pw_intail;
  600.     plNew->pchLine = pchData;
  601.     if (pw->pw_intail)
  602.         pw->pw_intail->plNext = plNew;
  603.     else
  604.         pw->pw_inhead = plNew;
  605.     pw->pw_intail = plNew;
  606.  
  607.     /* Once for the history list */
  608.     pchData = (char *) malloc(nLen + 1);
  609.     GetWindowText(pw->hEdit, pchData, nLen + 1);
  610.     pchData[nLen] = 0;
  611.     plNew = (struct line *) malloc(sizeof(struct line));
  612.     plNew->plNext = 0;
  613.     plNew->plPrev = pw->pw_histail;
  614.     plNew->pchLine = pchData;
  615.     if (pw->pw_histail)
  616.         pw->pw_histail->plNext = plNew;
  617.     else
  618.         pw->pw_hishead = plNew;
  619.     pw->pw_histail = plNew;
  620.     if (pw->nHistory >= pw->nHistMax)
  621.     {
  622.         plTemp = pw->pw_hishead;
  623.         pw->pw_hishead = plTemp->plNext;
  624.         pw->pw_hishead->plPrev = 0;
  625.         if (plTemp->pchLine)
  626.             free(plTemp->pchLine);
  627.         free(plTemp);
  628.     }
  629.     else
  630.     {
  631.         pw->nHistory++;
  632.     }
  633.     SetWindowText(pw->hEdit, "");
  634.     tkern_wakeup_call();
  635. }
  636.  
  637. static    BOOL
  638. CopyText(    HWND hWnd,
  639.         struct    per_window *pw)
  640. {
  641.     POINT    ptStart;
  642.     POINT    ptEnd;
  643.     int    i;
  644.     int    j;
  645.     int    nBytes;
  646.     struct    line *pl, *plSaved;
  647.     HGLOBAL    hmem;
  648.     char    *pchData;
  649.  
  650.     if (!pw->bMarkValid)
  651.     {
  652.         MessageBeep(MB_ICONSTOP);
  653.         return FALSE;
  654.     }
  655.     if (!OpenClipboard(hWnd))
  656.     {
  657.         MessageBeep(MB_ICONEXCLAMATION);
  658.         return FALSE;
  659.     }
  660.     EmptyClipboard();
  661.  
  662.     /* The clipboard wants CRLF separated lines. Figure out
  663.      * how many characters it will be.
  664.      */
  665.  
  666.     get_mark_coordinates(pw, &ptStart, &ptEnd);
  667.  
  668.     for (pl = pw->pw_tail, i = 0; pl && i < ptStart.y; pl = pl->plPrev, i++);
  669.     plSaved = pl;
  670.  
  671.     nBytes = 1; /* For the terminating NUL (not NULL) byte */
  672.  
  673.     while (i >= ptEnd.y)
  674.     {
  675.         nBytes += (pl->pchLine ? strlen(pl->pchLine) : 0);
  676.         if (ptEnd.y == i)
  677.             nBytes -= (pl->pchLine ? (strlen(pl->pchLine) - ptEnd.x) : 0);
  678.         else
  679.             nBytes += 2;
  680.         if (ptStart.y == i)
  681.             nBytes -= ptStart.x;
  682.  
  683.         i--;
  684.         pl = pl->plNext;
  685.     }
  686.  
  687.     hmem = GlobalAlloc(GMEM_MOVEABLE, nBytes);
  688.     pchData = GlobalLock(hmem);
  689.  
  690.     i = ptStart.y;
  691.     pl = plSaved;
  692.  
  693.     while (i >= ptEnd.y)
  694.     {
  695.         if (i == ptStart.y)
  696.             j = ptStart.x;
  697.         else
  698.             j = 0;
  699.  
  700.         if (i == ptEnd.y)
  701.         {
  702.             if (pl->pchLine)
  703.             {
  704.                 strncpy(pchData, pl->pchLine + j, ptEnd.x - j);
  705.                 pchData += ptEnd.x - j;
  706.             }
  707.         }
  708.         else
  709.         {
  710.             if (pl->pchLine)
  711.             {
  712.                 strcpy(pchData, pl->pchLine + j);
  713.                 pchData += strlen(pchData);
  714.             }
  715.             *pchData++ = '\r';
  716.             *pchData++ = '\n';
  717.         }
  718.         i--;
  719.         pl = pl->plNext;
  720.     }
  721.     *pchData = '\0';
  722.  
  723.     GlobalUnlock(hmem);
  724.     SetClipboardData(CF_TEXT, hmem);
  725.     CloseClipboard();
  726.     return TRUE;
  727. }
  728.  
  729. static    void
  730. PasteText(    HWND hWnd,
  731.         struct    per_window *pw)
  732. {
  733.     HGLOBAL    hmem;
  734.     char    *pchData;
  735.     char    *pchEOL;
  736.     char    *pchRemainder = 0;
  737.     char    *pchNow;
  738.     char    *pchTemp;
  739.     int    nTemp;
  740.     int    iRemainder;
  741.     DWORD    dwSelection;
  742.  
  743.     if (!OpenClipboard(hWnd))
  744.     {
  745.         MessageBeep(MB_ICONEXCLAMATION);
  746.         return;
  747.     }
  748.  
  749.     hmem = GetClipboardData(CF_TEXT);
  750.     if (!hmem)
  751.     {
  752.         MessageBeep(MB_ICONSTOP);
  753.         return;
  754.     }
  755.  
  756.     pchData = GlobalLock(hmem);
  757.  
  758.     while ((pchEOL = strchr(pchData, '\r')) != 0)
  759.     {
  760.         pchNow = malloc(pchEOL - pchData + 1);
  761.         strncpy(pchNow, pchData, pchEOL - pchData);
  762.         pchNow[pchEOL - pchData] = 0;
  763.         SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchNow);
  764.         free(pchNow);
  765.  
  766.         /* Remove the tail end of the line. This will get stuck
  767.          * back in once we get to the end of all this.
  768.          *
  769.          * Note that if we have done this once already, we know
  770.          * the selection is theoretically at the end of the window.
  771.          */
  772.  
  773.         if (!pchRemainder)
  774.         {
  775.             dwSelection = SendMessage(pw->hEdit, EM_GETSEL, 0, 0);
  776.             iRemainder = HIWORD(dwSelection);
  777.             nTemp = GetWindowTextLength(pw->hEdit);
  778.             pchTemp = malloc(nTemp + 1);
  779.             GetWindowText(pw->hEdit, pchTemp, nTemp + 1);
  780.             pchRemainder = malloc(nTemp - iRemainder + 1);
  781.             strcpy(pchRemainder, pchTemp + iRemainder);
  782.             pchTemp[iRemainder] = 0;
  783.             SetWindowText(pw->hEdit, pchTemp);
  784.             free(pchTemp);
  785.         }
  786.  
  787.         GotLine(pw);
  788.         pchData = pchEOL + 1;
  789.         if (*pchData == '\n')
  790.             pchData++;
  791.     }
  792.  
  793.     SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchData);
  794.     if (pchRemainder)
  795.     {
  796.         iRemainder = GetWindowTextLength(pw->hEdit);
  797.         SendMessage(pw->hEdit, EM_REPLACESEL, 0, (long) pchRemainder);
  798.         SendMessage(pw->hEdit, EM_SETSEL, TRUE, MAKELPARAM(iRemainder, iRemainder));
  799.         free(pchRemainder);
  800.     }
  801. }
  802.  
  803. static    void
  804. Scroll(    HWND    hWnd,
  805.     struct    per_window *pw,
  806.     WPARAM    wParam,
  807.     int    nPos)
  808. {
  809.     int    nNewPos;
  810.     RECT    rcScroll;
  811.     int    nRows;
  812.  
  813.     nNewPos = pw->nScrollPos;
  814.     GetClientRect(hWnd, &rcScroll);
  815.     rcScroll.bottom -= pw->cyChar + pw->cyChar / 5;
  816.     nRows = rcScroll.bottom / pw->cyChar - 1;
  817.  
  818.     switch(wParam)
  819.     {
  820.     case SB_BOTTOM:
  821.         nNewPos = 0;
  822.         break;
  823.  
  824.     case SB_LINEDOWN:
  825.         nNewPos--;
  826.         break;
  827.  
  828.     case SB_LINEUP:
  829.         nNewPos++;
  830.         break;
  831.  
  832.     case SB_PAGEUP:
  833.         nNewPos += nRows - 1;
  834.         break;
  835.  
  836.     case SB_PAGEDOWN:
  837.         nNewPos -= nRows - 1;
  838.         break;
  839.  
  840.     case SB_THUMBPOSITION:
  841.         nNewPos = nPos;
  842.         break;
  843.  
  844.     case SB_TOP:
  845.         nNewPos = pw->nLines;
  846.         break;
  847.     }
  848.     if (nNewPos > pw->nLines)
  849.         nNewPos = pw->nLines;
  850.     if (nNewPos < 0)
  851.         nNewPos = 0;
  852.  
  853.     SetScrollPos(hWnd, SB_VERT, pw->nLines - nNewPos, TRUE);
  854.     if (abs(pw->nScrollPos - nNewPos) >= nRows)
  855.         InvalidateRect(hWnd, &rcScroll, TRUE);
  856.     else
  857.         ScrollWindow(hWnd, 0,
  858.                  pw->cyChar * (nNewPos - pw->nScrollPos),
  859.                  &rcScroll, &rcScroll);
  860.     pw->nScrollPos = nNewPos;
  861.     if (nNewPos > 0)
  862.         pw->nUnscrolledLines = 0;
  863. }
  864.  
  865.  
  866. LRESULT    CALLBACK _export
  867. WindowProc(    HWND    hWnd,
  868.         UINT    wMsg,
  869.         WPARAM    wParam,
  870.         LPARAM    lParam)
  871. {
  872.     struct    per_window    *pw;
  873.     PAINTSTRUCT    ps;
  874.     TEXTMETRIC    tm;
  875.     HDC        hdc;
  876.  
  877.     pw = (struct per_window *) GetWindowLong(hWnd, 0);
  878.     switch(wMsg)
  879.     {
  880.     case WM_CREATE:
  881.         hdc = GetDC(hWnd);
  882.         GetTextMetrics(hdc, &tm);
  883.         ReleaseDC(hWnd, hdc);
  884.         pw = (struct per_window *) malloc(sizeof(struct per_window));
  885.         memset(pw, 0, sizeof(struct per_window));
  886.         pw->cxChar = tm.tmAveCharWidth;
  887.         pw->cyChar = tm.tmHeight + tm.tmExternalLeading;
  888.         pw->pw_head = (struct line *) malloc(sizeof(struct line));
  889.         pw->pw_tail = pw->pw_head;
  890.         pw->pw_head->plNext = pw->pw_head->plPrev = 0;
  891.         pw->pw_head->pchLine = 0;
  892.         pw->nHistMax = 20;
  893.         pw->nScrollLines = DEF_SCROLLLINES;
  894.         pw->nLinesMax = DEF_MAXLINES;
  895.         pw->nLines = 1;
  896.         pw->nUnscrolledLines = 0;
  897.         SetWindowLong(hWnd, 0, (long) pw);
  898.         PlaceEdit(hWnd, pw);
  899.         break;
  900.  
  901.     case WM_CLOSE:
  902.         if (!pw->bProgramClosed)
  903.         {
  904.             MessageBeep(MB_ICONSTOP);
  905.         }
  906.         else
  907.         {
  908.             window_destroy(hWnd);
  909.         }
  910.         return 0;
  911.  
  912.     case WM_PAINT:
  913.         PaintWindow(hWnd, pw);
  914.         return 0;
  915.  
  916.     case WM_SETFOCUS:
  917.         SetFocus(pw->hEdit);
  918.         return 0;
  919.  
  920.     case WM_LBUTTONDOWN:
  921.         MouseDown(hWnd, pw, LOWORD(lParam), HIWORD(lParam));
  922.         break;
  923.  
  924.     case WM_MOUSEMOVE:
  925.         if (pw->bHaveMouse)
  926.             MouseMove(hWnd, pw, LOWORD(lParam), HIWORD(lParam));
  927.         break;
  928.  
  929.     case WM_LBUTTONUP:
  930.         if (pw->bHaveMouse)
  931.             MouseUp(pw);
  932.         break;
  933.  
  934.     case WM_VSCROLL:
  935.         Scroll(hWnd, pw, wParam, LOWORD(lParam));
  936.         break;
  937.  
  938.     case WM_SYSCOMMAND:
  939.         switch(wParam)
  940.         {
  941.         case SC_COPY:
  942.             CopyText(hWnd, pw);
  943.             break;
  944.  
  945.         case SC_PASTE:
  946.             PasteText(hWnd, pw);
  947.             break;
  948.  
  949.         case SC_COPYPASTE:
  950.             if (CopyText(hWnd, pw))
  951.                 PasteText(hWnd, pw);
  952.             break;
  953.         }
  954.         break;
  955.  
  956.     case ENTER_HIT:
  957.         GotLine(pw);
  958.         break;
  959.  
  960.     case UP_HIT:
  961.         if (pw->pw_history)
  962.         {
  963.             if (pw->pw_history->plPrev)
  964.             {
  965.                 pw->pw_history = pw->pw_history->plPrev;
  966.             }
  967.             else
  968.             {
  969.                 MessageBeep(MB_ICONEXCLAMATION);
  970.                 break;
  971.             }
  972.         }
  973.         else if (pw->pw_histail)
  974.         {
  975.             pw->pw_history = pw->pw_histail;
  976.         }
  977.         else
  978.         {
  979.             MessageBeep(MB_ICONEXCLAMATION);
  980.             break;
  981.         }
  982.         SetWindowText(pw->hEdit, pw->pw_history->pchLine);
  983.         break;
  984.  
  985.     case DOWN_HIT:
  986.         if (pw->pw_history)
  987.         {
  988.             if (pw->pw_history->plNext)
  989.             {
  990.                 pw->pw_history = pw->pw_history->plNext;
  991.             }
  992.             else
  993.             {
  994.                 MessageBeep(MB_ICONEXCLAMATION);
  995.                 break;
  996.             }
  997.         }
  998.         else if (pw->pw_hishead)
  999.         {
  1000.             pw->pw_history = pw->pw_hishead;
  1001.         }
  1002.         else
  1003.         {
  1004.             MessageBeep(MB_ICONEXCLAMATION);
  1005.             break;
  1006.         }
  1007.         SetWindowText(pw->hEdit, pw->pw_history->pchLine);
  1008.         break;
  1009.     }
  1010.     return DefWindowProc(hWnd, wMsg, wParam, lParam);
  1011. }
  1012.  
  1013.  
  1014.  
  1015. #pragma argsused
  1016. int
  1017. window_open(    char    const *pchPath,
  1018.         int    iMode,
  1019.         int    iAccess)
  1020. {
  1021.     HWND    hWnd;
  1022.     HMENU    hmenuSys;
  1023.  
  1024.     if (!bRegistered)
  1025.     {
  1026.         WNDCLASS wc;
  1027.  
  1028.         wc.style = CS_GLOBALCLASS |
  1029.                CS_HREDRAW |
  1030.                CS_VREDRAW;
  1031.         wc.lpfnWndProc = WindowProc;
  1032.         wc.cbClsExtra = 0;
  1033.         wc.cbWndExtra = sizeof(struct per_window *);
  1034.         wc.hInstance = hInstance;
  1035.         wc.hIcon = LoadIcon(hInstance, "TKERN_ICO");
  1036.         wc.hCursor = (HCURSOR) IDC_IBEAM;
  1037.         wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  1038.         wc.lpszMenuName = 0;
  1039.         wc.lpszClassName = "Troy's Kernel Window";
  1040.         RegisterClass(&wc);
  1041.  
  1042.         iDevice = get_device_number("window");
  1043.     }
  1044.  
  1045.     hWnd = CreateWindow(    "Troy's Kernel Window",
  1046.                 pchPath,
  1047.                 WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_VSCROLL,
  1048.                 CW_USEDEFAULT,
  1049.                 0,
  1050.                 CW_USEDEFAULT,
  1051.                 0,
  1052.                 0,
  1053.                 0,
  1054.                 hInstance,
  1055.                 0
  1056.             );
  1057.     if (!hWnd)
  1058.     {
  1059.         nError = ENOMEM;
  1060.         return -1;
  1061.     }
  1062.     else
  1063.     {
  1064.         LockManager();
  1065.         hmenuSys = GetSystemMenu(hWnd, FALSE);
  1066.         AppendMenu(hmenuSys, MF_SEPARATOR, 0, 0);
  1067.         AppendMenu(hmenuSys, MF_STRING, SC_COPY, "C&opy");
  1068.         AppendMenu(hmenuSys, MF_STRING, SC_PASTE, "&Paste");
  1069.         AppendMenu(hmenuSys, MF_STRING, SC_COPYPASTE, "Cop&y and Paste");
  1070.         EnableMenuItem(hmenuSys, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
  1071.         ShowWindow(hWnd, SW_SHOW);
  1072.         return (int) hWnd;
  1073.     }
  1074. }
  1075.  
  1076. static    void
  1077. add_to_line(    struct    line    *pl,
  1078.         char    const    *pchBuffer,
  1079.         int    nBytes)
  1080. {
  1081.     char    *pchString;
  1082.  
  1083.     if (!nBytes)
  1084.         return;
  1085.     pchString = (char *) malloc(nBytes +
  1086.             (pl->pchLine ? strlen(pl->pchLine) : 0) + 1);
  1087.     if (pl->pchLine)
  1088.         strcpy(pchString, pl->pchLine);
  1089.     else
  1090.         *pchString = 0;
  1091.     pchString[strlen(pchString) + nBytes] = 0;
  1092.     memcpy(pchString + strlen(pchString), pchBuffer, nBytes);
  1093.     if (pl->pchLine)
  1094.         free(pl->pchLine);
  1095.     pl->pchLine = pchString;
  1096. }
  1097.         
  1098.  
  1099. int
  1100. window_write(    int    id,
  1101.         char    const *pchBuffer,
  1102.         int    nBytes)
  1103. {
  1104.     HWND    hWnd = (HWND) id;
  1105.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1106.     int    nLines = 0;
  1107.     char    *pchNewLine;
  1108.     char    const *c = pchBuffer;
  1109.     struct    line *plTemp;
  1110.     int    nLeft = nBytes;
  1111.     RECT    rcRedraw;
  1112.  
  1113.     if (!nBytes)
  1114.         return 0;
  1115.  
  1116.     while (nLeft--)
  1117.     {
  1118.         if (*c++ == '\n')
  1119.         {
  1120.             add_to_line(pw->pw_tail, pchBuffer, c - pchBuffer - 1);
  1121.             plTemp = (struct line *) malloc(sizeof(struct line));
  1122.             plTemp->pchLine = 0;
  1123.             plTemp->plNext = 0;
  1124.             plTemp->plPrev = pw->pw_tail;
  1125.             pw->pw_tail->plNext = plTemp;
  1126.             pw->pw_tail = plTemp;
  1127.             pchBuffer = c;
  1128.             nLines++;
  1129.         }
  1130.     }
  1131.     if (c != pchBuffer)
  1132.         add_to_line(pw->pw_tail, pchBuffer, c - pchBuffer);
  1133.     GetClientRect(hWnd, &rcRedraw);
  1134.     rcRedraw.top = rcRedraw.bottom - pw->cyChar - pw->cyChar / 5 * 2;
  1135.     InvalidateRect(hWnd, &rcRedraw, TRUE);
  1136.     if (nLines)
  1137.     {
  1138.         /* Rather than scrolling every line, which
  1139.          * is somewhat slow, scroll after some
  1140.          * number of lines as set by the user.
  1141.          * This is processed via a posted message,
  1142.          * so once an app starts flushing messages,
  1143.          * any outstanding scrolling should be
  1144.          * processed.
  1145.          */
  1146.         if (!pw->nScrollPos)
  1147.         {
  1148.             pw->nUnscrolledLines += nLines;
  1149.             if (pw->nUnscrolledLines >= pw->nScrollLines)
  1150.                 FlushMessages();
  1151.         }
  1152.         MoveMark(pw, nLines);
  1153.         pw->nLines += nLines;
  1154.         while (pw->nLines > pw->nLinesMax)
  1155.         {
  1156.             plTemp = pw->pw_head;
  1157.             pw->pw_head = plTemp->plNext;
  1158.             if (plTemp->pchLine)
  1159.                 free(plTemp->pchLine);
  1160.             free(plTemp);
  1161.             pw->pw_head->plPrev = 0;
  1162.             pw->nLines--;
  1163.         }
  1164.         if (pw->nScrollPos)
  1165.             pw->nScrollPos += nLines;
  1166.         SetScrollRange(hWnd, SB_VERT, 0, pw->nLines, FALSE);
  1167.         SetScrollPos(hWnd, SB_VERT, pw->nLines - pw->nScrollPos, TRUE);
  1168.     }
  1169.     return    nBytes;
  1170. }
  1171.  
  1172. int
  1173. window_read(    int    id,
  1174.         char    *pchBuffer,
  1175.         int    nBytes)
  1176. {
  1177.     HWND    hWnd = (HWND) id;
  1178.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1179.     struct    line    *pl;
  1180.     char    *pchNewLine;
  1181.     int    iLen;
  1182.  
  1183.     if (!pw->pw_inhead)
  1184.         return FR_NOTREADY;
  1185.  
  1186.     pl = pw->pw_inhead;
  1187.  
  1188.     iLen = strlen(pl->pchLine);
  1189.     if (iLen >= nBytes)
  1190.     {
  1191.         memcpy(pchBuffer, pl->pchLine, nBytes);
  1192.         pchNewLine = (char *) malloc(iLen + 1 - nBytes);
  1193.         memcpy(pchNewLine, pl->pchLine + nBytes, iLen + 1 - nBytes);
  1194.         free(pl->pchLine);
  1195.         pl->pchLine = pchNewLine;
  1196.     }
  1197.     else
  1198.     {
  1199.         memcpy(pchBuffer, pl->pchLine, iLen);
  1200.         pchBuffer[iLen] = '\n';
  1201.         pw->pw_inhead = pl->plNext;
  1202.         if (!pl->plNext)
  1203.             pw->pw_intail = 0;
  1204.         free(pl->pchLine);
  1205.         free(pl);
  1206.         nBytes = iLen + 1;
  1207.     }
  1208.     window_write(id, pchBuffer, nBytes);
  1209.     return nBytes;
  1210. }
  1211.  
  1212. int
  1213. window_close(    int    id)
  1214. {
  1215.     HWND    hWnd = (HWND) id;
  1216.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1217.     HMENU    hmenuSys = GetSystemMenu(hWnd, TRUE);
  1218.     char    *pchOldText;
  1219.     char    *pchNewText;
  1220.     int    nTextLen;
  1221.  
  1222.     EnableMenuItem(hmenuSys, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
  1223.     pw->bProgramClosed = TRUE;
  1224.     nTextLen = GetWindowTextLength(hWnd);
  1225.     pchOldText = (char *) malloc(nTextLen + 1);
  1226.     GetWindowText(hWnd, pchOldText, nTextLen + 1);
  1227.     pchOldText[nTextLen] = 0;
  1228.     pchNewText = malloc(nTextLen + 12);
  1229.     strcpy(pchNewText, "(Inactive ");
  1230.     strcat(pchNewText, pchOldText);
  1231.     strcat(pchNewText, ")");
  1232.     free(pchOldText);
  1233.     SetWindowText(hWnd, pchNewText);
  1234.     free(pchNewText);
  1235.     return 0;
  1236. }
  1237.  
  1238. static int
  1239. window_destroy(HWND hWnd)
  1240. {
  1241.     struct    line    *pl, *plNext;
  1242.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1243.  
  1244.     DestroyWindow(hWnd);
  1245.     for (pl = pw->pw_head; pl; pl = plNext)
  1246.     {
  1247.         plNext = pl->plNext;
  1248.         if (pl->pchLine)
  1249.             free(pl->pchLine);
  1250.         free(pl);
  1251.     }
  1252.     for (pl = pw->pw_hishead; pl; pl = plNext)
  1253.     {
  1254.         plNext = pl->plNext;
  1255.         if (pl->pchLine)
  1256.             free(pl->pchLine);
  1257.         free(pl);
  1258.     }
  1259.     for (pl = pw->pw_inhead; pl; pl = plNext)
  1260.     {
  1261.         plNext = pl->plNext;
  1262.         if (pl->pchLine)
  1263.             free(pl->pchLine);
  1264.         free(pl);
  1265.     }
  1266.     free(pw);
  1267.     UnlockManager();
  1268.     return 0;
  1269. }
  1270.  
  1271. void
  1272. CheckLimits(    HWND    hWnd,
  1273.         struct per_window *pw)
  1274. {
  1275.     struct    line    *plTemp;
  1276.  
  1277.     while (pw->nLines > pw->nLinesMax)
  1278.     {
  1279.         plTemp = pw->pw_head;
  1280.         pw->pw_head = plTemp->plNext;
  1281.         if (plTemp->pchLine)
  1282.             free(plTemp->pchLine);
  1283.         free(plTemp);
  1284.         pw->pw_head->plPrev = 0;
  1285.         pw->nLines--;
  1286.     }
  1287.  
  1288.     while (pw->nHistory > pw->nHistMax)
  1289.     {
  1290.         plTemp = pw->pw_hishead;
  1291.         pw->pw_hishead = plTemp->plNext;
  1292.         pw->pw_hishead->plPrev = 0;
  1293.         if (plTemp->pchLine)
  1294.             free(plTemp->pchLine);
  1295.         free(plTemp);
  1296.         pw->nHistory--;
  1297.     }
  1298.     pw->pw_history = 0;
  1299.     SetScrollRange(hWnd, SB_VERT, 0, pw->nLines, FALSE);
  1300. }
  1301.  
  1302. void
  1303. GetWindowSize(    HWND    hWnd,
  1304.         struct per_window *pw,
  1305.         struct winsize *wsize)
  1306. {
  1307.     RECT    rcWindow;
  1308.  
  1309.     GetClientRect(hWnd, &rcWindow);
  1310.     wsize->ws_xpixel = rcWindow.right;
  1311.     wsize->ws_ypixel = rcWindow.bottom;
  1312.     wsize->ws_col = rcWindow.right / pw->cxChar;
  1313.     wsize->ws_row = (rcWindow.bottom - pw->cyChar / 5 * 2) / pw->cyChar;
  1314. }
  1315.  
  1316. void
  1317. SetWindowSize(    HWND    hWnd,
  1318.         struct per_window *pw,
  1319.         struct winsize *wsize)
  1320. {
  1321.     RECT    rcClient;
  1322.     RECT    rcWindow;
  1323.     int    xExtra;
  1324.     int    yExtra;
  1325.     int    xSize;
  1326.     int    ySize;
  1327.  
  1328.     GetClientRect(hWnd, &rcClient);
  1329.     GetWindowRect(hWnd, &rcWindow);
  1330.     xExtra = (rcWindow.right - rcWindow.left) - rcClient.right;
  1331.     yExtra = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
  1332.  
  1333.     if (wsize->ws_col)
  1334.         xSize = wsize->ws_col * pw->cxChar;
  1335.     else if (wsize->ws_xpixel)
  1336.         xSize = wsize->ws_xpixel;
  1337.     else
  1338.         xSize = rcClient.right;
  1339.  
  1340.     if (wsize->ws_row)
  1341.         ySize = wsize->ws_row * pw->cyChar + pw->cyChar / 5 * 2;
  1342.     else if (wsize->ws_ypixel)
  1343.         ySize = wsize->ws_ypixel;
  1344.     else
  1345.         ySize = rcClient.bottom;
  1346.  
  1347.     MoveWindow(hWnd,
  1348.             rcWindow.left,
  1349.             rcWindow.top,
  1350.             xSize + xExtra,
  1351.             ySize + yExtra,
  1352.             TRUE);
  1353. }
  1354.  
  1355. int
  1356. window_ioctl(    int    fd,
  1357.         struct tk_ioctl *tki)
  1358. {
  1359.     HWND    hWnd = (HWND) fd;
  1360.     struct    wio_parms * const wiop = (struct wio_parms *) tki->achBuffer;
  1361.     struct    per_window *pw = (struct per_window *) GetWindowLong(hWnd, 0);
  1362.  
  1363.     switch(tki->nIOCtl)
  1364.     {
  1365.     case WIOCGETHANDLE:
  1366.         return fd;
  1367.  
  1368.     case WIOCGETNAME:
  1369.         return GetWindowText(hWnd, tki->achBuffer, tki->nSize);
  1370.  
  1371.     case WIOCSETNAME:
  1372.         SetWindowText(hWnd, tki->achBuffer);
  1373.         return 0;
  1374.  
  1375.     case WIOCGETPARMS:
  1376.         wiop->wiop_display_lines = pw->nLinesMax;
  1377.         wiop->wiop_history_lines = pw->nHistMax;
  1378.         wiop->wiop_scroll_lines = pw->nScrollLines;
  1379.         return 0;
  1380.  
  1381.     case WIOCSETPARMS:
  1382.         pw->nLinesMax = wiop->wiop_display_lines;
  1383.         pw->nHistMax = wiop->wiop_history_lines;
  1384.         pw->nScrollLines = wiop->wiop_scroll_lines;
  1385.         CheckLimits(hWnd, pw);
  1386.         return 0;
  1387.  
  1388.     case TIOCGWINSZ:
  1389.         GetWindowSize(hWnd, pw, (struct winsize *) tki->achBuffer);
  1390.         return 0;
  1391.  
  1392.     case TIOCSWINSZ:
  1393.         SetWindowSize(hWnd, pw, (struct winsize *) tki->achBuffer);
  1394.         return 0;
  1395.  
  1396.     default:
  1397.         nError = EINVAL;
  1398.         return -1;
  1399.     }
  1400. }
  1401.